//
// Created on 2024/4/18.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#include <js_native_api.h>
#include <js_native_api_types.h>
#include <type_traits>
#include "NapiValueConverter.h"

#ifndef _JSFUNCTION_H_
#define _JSFUNCTION_H_
/**
 * 封装Js方法
 */
class JsFunction {
private:
    
    
public:
    napi_ref funcRef;
    napi_env env;
    char *name = nullptr;

    explicit JsFunction(char *name, napi_env env, napi_ref funcRef) : name(name), env(env), funcRef(funcRef) {}

    explicit JsFunction(char *name, napi_env env) : name(name), env(env) {}

    explicit JsFunction(char *name) : name(name) {}

    /**
     * invoke 方法调用带返回类型
     * @tparam ReturnType
     * @tparam Args
     */
    template <typename ReturnType, typename... Args>
    typename std::enable_if<!std::is_same<ReturnType, void>::value, ReturnType>::type invoke(Args... args) {
        napi_value global;
        napi_status status = napi_get_global(env, &global);
        // if (status != napi_ok) return;

        napi_value func;
        status = napi_get_reference_value(env, funcRef, &func);

        napi_value jsArgs[sizeof...(Args)] = {NapiValueConverter::ToNapiValue(env, args)...};
        napi_value return_val;
        status = napi_call_function(env, global, func, sizeof...(Args), jsArgs, &return_val);

        ReturnType value;
        if (!NapiValueConverter::ToCppValue(env, return_val, value)) {
            // Handle error here
        }
        return value;
    }

       
    /**
     * invoke方法调用不带返回类型
     * @tparam ReturnType
     * @tparam Args
     */
    template <typename ReturnType, typename... Args>
    typename std::enable_if<std::is_same<ReturnType, void>::value, void>::type invoke(Args... args) {
        napi_value global;
        napi_status status = napi_get_global(env, &global);
        if (status != napi_ok)
            return;

        napi_value func;
        status = napi_get_reference_value(env, funcRef, &func);

        napi_value jsArgs[sizeof...(Args)] = {NapiValueConverter::ToNapiValue(env, args)...};
        napi_value return_val;
        status = napi_call_function(env, global, func, sizeof...(Args), jsArgs, &return_val);
    }
};

#endif